//
// AtaDevice.cpp
// Usage: Defines the interface for a device representing an ATA disk.
// From: jimix
// ImportDate: 2009-04-27
//
#include "AtaDevice.h"
#include <stdio.h>
#include <string.h>
#include "bootutil.h"

AtaDevice::AtaDevice(DWORD dwController, DWORD dwDrive)
	: m_dwController(dwController), m_dwDrive(dwDrive)
{
	ident = new unsigned short[256];

	/* Probe to see if selected drive exist */
	unsigned long cap = __IDEProbe();
	if(!(cap&(1<<dwController | 1<<(2+dwController*2+dwDrive))))
		return;

	/* Wait for IDE to ready */
	if(FAILED(__IDEWaitForDrive(m_dwController, m_dwDrive)))
		return;

	/* Identify IDE dirve */
	if(FAILED(__IDEIdentifyDrive(m_dwController, m_dwDrive, (char *)ident, 512)))
		return;

	// Read partition table.
	unsigned char buffer[512];
	ReadSector(0x0, 1, buffer);
	// Partition table starts at 0x1be and is 64 bytes long.
	memcpy((unsigned char*)&m_Partitions, (unsigned char*)(((unsigned long)buffer)+0x1be), 64);
}

void AtaDevice::GetModelName(char *buf, int maxLen)
{
	if (maxLen < 41)
		return;
	for (int i = 0; i < 20; i++)
	{
		buf[i*2]  = ident[0x1B+i] >> 8;
		buf[i*2+1] = ident[0x1B+i] & 0xFF;
	}
	for (int i = 39; i > 0; i--)
		if (buf[i] != ' ')
			break;
		else
			buf[i] = '\0';
	buf[40] = '\0';
}

void AtaDevice::GetSerialNumber(char *buf, int maxLen)
{
	if (maxLen < 21)
		return;
	for (int i = 0; i < 10; i++)
	{
		buf[i*2]  = ident[0x0A+i] >> 8;
		buf[i*2+1]= ident[0x0A+i] & 0xFF;
	}
	for (int i = 20; i > 0; i--)
		if (buf[i] != ' ')
			break;
		else
			buf[i] = '\0';
}

void AtaDevice::GetFirmwareRevision(char *buf, int maxLen)
{
	if (maxLen < 9)
		return;
	for (int i = 0; i < 4; i++)
	{
		buf[i*2]  = ident[0x17+i] >> 8;
		buf[i*2+1]= ident[0x17+i] & 0xFF;
	}
	for (int i = 8; i > 0; i--)
		if (buf[i] != ' ')
			break;
		else
			buf[i] = '\0';
}

bool AtaDevice::ReadSector(unsigned long lba, int cnt, unsigned char *buf)
{
	return FAILED(__IDEReadFromPortsLBA28(
		m_dwController,
		m_dwDrive,
		lba,
		cnt,
		buf,
		cnt*512
	));
}

